/**
 * 
 */
package com.dalonedrow.engine.sprite.base;

import com.dalonedrow.engine.systems.Render;
import com.dalonedrow.engine.systems.Time;
import com.dalonedrow.globalvariables.constants.hq.GlobalConstants;

/**
 * @author Donald
 */
public final class ParticleEmitter {
	/** Pi divided by 180. */
	public static final double	PI_DIV_180	= Math.PI * GlobalConstants.DIV_180;
	private int					behavior;
	/** the angle in which the particles are being emitted. */
	private double				direction;
	private boolean				exists;
	/** the time emitter's last frame started. */
	private long				frameStart;
	/** the image reference all particles use. */
	private int					imageRef;
	/**
	 * the distance in pixels which a particle can travel from the emitter
	 * before being recalled.
	 */
	private float				length;
	/** the maximum number of particles in play. */
	private int					max;
	/** the maximum alpha value for a particle. a number between 0.0 and 1.0. */
	private float				maxA;
	/** the maximum blue value for a particle. a number between 0.0 and 1.0. */
	private float				maxB;
	/** the maximum green value for a particle. a number between 0.0 and 1.0. */
	private float				maxG;
	/** the maximum red value for a particle. a number between 0.0 and 1.0. */
	private float				maxR;
	/** the minimum alpha value for a particle. a number between 0.0 and 1.0. */
	private float				minA;
	/** the minimum blue value for a particle. a number between 0.0 and 1.0. */
	private float				minB;
	/** the minimum green value for a particle. a number between 0.0 and 1.0. */
	private float				minG;
	/** the minimum red value for a particle. a number between 0.0 and 1.0. */
	private float				minR;
	/** the parent component's id. */
	private int					parentId;
	/** the list of particles being emitted. */
	private SpriteBase[]		particles;
	/** the time in nanoseconds when the particle started. */
	private long[]				particleStart;
	/** the position of the emitter. */
	private SimpleVector3				position;
	/** the scale at which particles are magnified. */
	private float				scale;
	/** the spread in pixels that the angle set. */
	private int					spread;
	/** the time the emitter started. */
	private long				timeStart;
	/** the emitter's velocity. */
	private float				velocity;
	/** Creates a new instance of {@link ParticleEmitter}. */
	public ParticleEmitter() {
		// initialize particles to defaults
		imageRef = -1;
		max = 100;
		length = 100;
		direction = 0;
		minA = 254f / 255f;
		maxA = 1f;
		minR = 0;
		maxR = 1f;
		minG = 0;
		maxG = 1f;
		minB = 0;
		maxB = 1f;
		spread = 10;
		velocity = 1.0f;
		scale = 1.0f;
		exists = false;
		particles = new SpriteBase[0];
		particleStart = new long[0];
	}
	/**
	 * Adds a particle to the emitter.
	 * @param particle the particle
	 */
	public void addParticle(final SpriteBase particle) {
		int index = -1;
		for (int i = 0; i < particles.length; i++) {
			if (particles[i] == null) {
				particles[i] = particle;
				particleStart[i] = Time.getInstance().getFrameStart();
				index = i;
				break;
			}
		}
		if (index == -1) {
			// extend the arrays
			SpriteBase[] dest = new SpriteBase[particles.length + 1];
			System.arraycopy(particles, 0, dest, 0, particles.length);
			dest[particles.length] = particle;
			particles = dest;
			dest = null;
			// extend the arrays
			long[] destl = new long[particleStart.length + 1];
			System.arraycopy(
					particleStart, 0, destl, 0, particleStart.length);
			destl[particleStart.length] =
					Time.getInstance().getFrameStart();
			particleStart = destl;
			destl = null;
		}
	}
	/**
	 * Determines if the {@link ParticleEmitter} exists and is ready to update
	 * and render.
	 * @return true if the {@link ParticleEmitter} has been configured and is
	 *         ready to render; false otherwise
	 */
	public boolean exists() {
		return exists;
	}
	/**
	 * Gets the {@link ParticleEmitter}'s behavior.
	 * @return <code>int</code>
	 */
	public int getBehavior() {
		return behavior;
	}
	public double getDirection() {
		return direction;
	}
	/**
	 * Gets the time emitter's last frame started.
	 * @return <code>long</code>
	 */
	public long getFrameStart() {
		return frameStart;
	}
	/**
	 * Gets the image reference all particles use.
	 * @return <code>int</code>
	 */
	public int getImageRef() {
		return imageRef;
	}
	/**
	 * Gets the distance in pixels which a particle can travel from the emitter
	 * before being recalled.
	 * @return <code>float</code>
	 */
	public float getLength() {
		return length;
	}
	/**
	 * Gets the maximum number of particles that can be emitted.
	 * @return <code>int</code>
	 */
	public int getMax() {
		return max;
	}
	/**
	 * Gets the maximum alpha value for a particle, a number between 0.0 and
	 * 1.0.
	 * @return <code>float</code>
	 */
	public float getMaxA() {
		return maxA;
	}
	/**
	 * Gets the maximum blue value for a particle, a number between 0.0 and 1.0.
	 * @return <code>float</code>
	 */
	public float getMaxB() {
		return maxB;
	}
	/**
	 * Gets the maximum green value for a particle, a number between 0.0 and
	 * 1.0.
	 * @return <code>float</code>
	 */
	public float getMaxG() {
		return maxG;
	}
	/**
	 * Gets the maximum red value for a particle, a number between 0.0 and 1.0.
	 * @return <code>float</code>
	 */
	public float getMaxR() {
		return maxR;
	}
	/**
	 * Gets the minimum alpha value for a particle, a number between 0.0 and
	 * 1.0.
	 * @return <code>float</code>
	 */
	public float getMinA() {
		return minA;
	}
	/**
	 * Gets the minimum blue value for a particle, a number between 0.0 and 1.0.
	 * @return <code>float</code>
	 */
	public float getMinB() {
		return minB;
	}
	/**
	 * Gets the minimum green value for a particle, a number between 0.0 and
	 * 1.0.
	 * @return <code>float</code>
	 */
	public float getMinG() {
		return minG;
	}
	/**
	 * Gets the minimum red value for a particle, a number between 0.0 and 1.0.
	 * @return <code>float</code>
	 */
	public float getMinR() {
		return minR;
	}
	/**
	 * Gets the number of particles that have been emitted.
	 * @return <code>int</code>
	 */
	public int getNumParticles() {
		return particles.length;
	}
	/**
	 * Gets the parent component's id.
	 * @return <code>int</code>
	 */
	public int getParentId() {
		return parentId;
	}
	/**
	 * Gets a specific particle.
	 * @param index the particle's index
	 * @return {@link SpriteBase};
	 */
	public SpriteBase getParticle(final int index) {
		return particles[index];
	}
	/**
	 * Gets the time a specific particle started.
	 * @param index the particle's index
	 * @return <code>long</code>
	 */
	public long getParticleStart(final int index) {
		return particleStart[index];
	}
	/**
	 * Gets the emitter's position.
	 * @return {@link SimpleVector3}
	 */
	public SimpleVector3 getPosition() {
		return position;
	}
	/**
	 * Gets the scale at which particles are magnified.
	 * @return <code>float</code>
	 */
	public float getScale() {
		return scale;
	}
	/**
	 * Gets the spread in pixels that the angle set.
	 * @return <code>int</code>
	 */
	public int getSpread() {
		return spread;
	}
	/**
	 * Gets the time the emitter started.
	 * @return <code>long</code>
	 */
	public long getTimeStart() {
		return timeStart;
	}
	/**
	 * Gets the emitter's velocity.
	 * @return <code>float</code>
	 */
	public float getVelocity() {
		return velocity;
	}
	/** Renders all particles. */
	public void render() {
		if (exists) {
			for (int i = 0; i < particles.length; i++) {
				Render.getInstance().registerEntity(particles[i]);
			}
		}
	}
	/**
	 * Sets the emitter's alpha range.
	 * @param alphaMin the minimum alpha
	 * @param alphaMax the maximum alpha
	 */
	public void setAlphaRange(final float alphaMin, final float alphaMax) {
		minA = alphaMin;
		if (minA < 0f) {
			minA = 0f;
		}
		maxA = alphaMax;
		if (maxA < 1f) {
			maxA = 1f;
		}
	}
	/**
	 * Sets the {@link ParticleEmitter}'s behavior.
	 * @param val the value to set
	 */
	public void setBehavior(final int val) {
		behavior = val;
	}
	/**
	 * Sets the emitter's color range.
	 * @param r1 the minimum red value
	 * @param g1 the minimum green value
	 * @param b1 the minimum blue value
	 * @param r2 the maximum red value
	 * @param g2 the maximum green value
	 * @param b2 the maximum blue value
	 */
	public void setColorRange(final int r1, final int g1, final int b1,
			final int r2, final int g2, final int b2) {
		minR = r1;
		maxR = r2;
		if (minR < 0f) {
			minR = 0f;
		}
		if (maxR < 1f) {
			maxR = 1f;
		}
		minG = g1;
		maxG = g2;
		if (minG < 0f) {
			minG = 0f;
		}
		if (maxG < 1f) {
			maxG = 1f;
		}
		minB = b1;
		maxB = b2;
		if (minB < 0f) {
			minB = 0f;
		}
		if (maxB < 1f) {
			maxB = 1f;
		}
	}
	/**
	 * Sets the angle at which particles emit. Only values between 0 and 359 are
	 * allowed. The direction is based on the angles of a circle; 0 degrees emit
	 * particles to the right, 90 degrees will go to the top, etc.
	 * @param angle the angle
	 */
	public void setDirection(final double angle) {
		direction = angle;
		if (direction < 0) {
			direction = 0;
		} else if (direction > 359) {
			direction = 359;
		}
	}
	/**
	 * Sets the flag indicating the {@link ParticleEmitter} exists and can be
	 * rendered.
	 * @param flag the flag
	 */
	public void setExists(final boolean flag) {
		exists = flag;
		if (!exists) {
			particles = new SpriteBase[0];
			particleStart = new long[0];
		}
	}
	/**
	 * Sets the time emitter's last frame started.
	 * @param time the time to set
	 */
	public void setFrameStart(final long time) {
		frameStart = time;
	}
	public void setImage(final int imgRef) {
		imageRef = imgRef;
	}
	/**
	 * Sets the distance in pixels which a particle can travel from the emitter
	 * before being recalled.
	 * @param value the distance
	 */
	public void setLength(final float value) {
		length = value;
	}
	public void setMax(final int num) {
		max = num;
	}
	/**
	 * Sets the parent component's id.
	 * @param id the id to set
	 */
	public void setParentId(final int id) {
		parentId = id;
	}
	/**
	 * Sets the time a specific particle started.
	 * @param index the particle's index
	 * @param time the time to set
	 */
	public void setParticleStart(final int index, final long time) {
		particleStart[index] = time;
	}
	public void setPosition(final double x, final double y) {
		position.set(x, y, 0);
	}
	public void setPosition(final SimpleVector3 vec) {
		position = vec;
	}
	public void setScale(final float value) {
		scale = value;
	}
	public void setSpread(final int value) {
		spread = value;
	}
	/**
	 * Sets the frameStart
	 * @param frameStart the frameStart to set
	 */
	public void setTimeStart(long time) {
		timeStart = time;
	}
	/**
	 * Sets the emitter's velocity.
	 * @param value the new value
	 */
	public void setVelocity(final float value) {
		velocity = value;
	}
	/** Stops the emitter. */
	public void stop() {
		exists = false;
		particles = new SpriteBase[0];
		particleStart = new long[0];
	}
}
